#ifndef _L_BV_TREE_120118_BV_NODE_H
#define _L_BV_TREE_120118_BV_NODE_H

#include <ltypes.h>
#include <lmacros.h>
#include <lutility.h>
#include <ltriMesh.h>

#include "BoundingVolume.h"
#include "NormalCone.h"
#include "BVTree.h"

LLIB_BEGIN
namespace geom {

/* symbol intro */
typedef util::EmptyClass EmptyClass;

/* The generic bounding volume node class.
 * We only use the partial specialized version.
 */
template <unsigned BVTreeType, typename BV_t, typename NC_t = EmptyClass>
class BVNode;

/* Here are BVTree type macros */
#define BVTREE_TYPE_CBT     0   // The BVTree based on Complete Binary Tree
//#define BVTREE_TYPE_LINK    1

#pragma region The BVNode of BVTree_CBT

/* The bounding volume node of Complete Binary Tree BVTree.
 * WITHOUT Normal Cone self-collision culling strategy.
 */
template <typename BV_t>
class BVNode<BVTREE_TYPE_CBT, BV_t, EmptyClass> {
private:
    typedef BVNode<BVTREE_TYPE_CBT, BV_t, EmptyClass> mine_t;
public:
    /* The bounding volume type definition */
    typedef BV_t BV;

    /* Root node check */
    inline Boolean IsRoot() const { return this == _tree->_nodeList; }

    /* Leaf node check */
    inline Boolean IsLeaf() const { return isLeaf(); }

    /* Get the corresponding mesh face of current leaf node */
    MeshFace GetLeafMeshFace() const {
        Int32 leafIndex = getLeafIndex();
        Int32 faceIndex = _tree->_leafIndexList[leafIndex];
        return _tree->_mesh->GetFace(faceIndex);
    }

    /* Get the depth of current node in tree
     * Note: the depth of root is 0
     */
    Int32 GetDepth() const {
        Int32 index = getNodeIndex() + 1;
        Int32 depth = -1;
        while(index != 0) {
            ++depth;
            index >>= 1;
        }
        return depth;
    }

    /* Parent node query
     * Note: return NULL when current node is root.
     */
    inline mine_t* GetParent() const {
        if(IsRoot()) return NULL;
        Int32 index = (getNodeIndex() - 1) / 2;
        return _tree->_nodeList + index;
    }

    /* Child node query
     * Note: return NULL when current node has no left/right child
     */
    inline mine_t* GetChildLeft() const {
        if(isLeaf()) return NULL;
        Int32 index = getNodeIndex() * 2 + 1;
        return _tree->_nodeList + index;
    }
    inline mine_t* GetChildRight() const {
        if(isLeaf()) return NULL;
        Int32 index = getNodeIndex() * 2 + 2;
        return _tree->_nodeList + index;
    }

    /* Update node state */
    void Update() {
        if(!isLeaf()) {
            // in our case (the complete binary tree), 
            // every internal node has both leaf and right child,
            // so we merge BVs of both childs.
            mine_t* lchild = GetChildLeft();
            mine_t* rchild = GetChildRight();
            _bv = BV_t::Merge(lchild->_bv, rchild->_bv);
        } else {
            // get the bv of a leaf triangle, then update BV
            MeshFace triangle = GetLeafMeshFace();
            _bv.Update(triangle);
        }
    }

    /* Collision culling
     * Check whether two mesh region collide, which is useful for
     * speeding up collision detection.
     * Return TURE when NO collision we can guarantee, otherwise return FALSE.
     */
    inline Boolean CollisionCulling(const mine_t* another) const { return CollisionCulling(this, another); }
    inline static Boolean CollisionCulling(const mine_t* first, const mine_t* second) { return !first->_bv.Intersect(second->_bv); }

    /* Self collision culling
     * Check whether the mesh region has a self collision, which is useful for
     * speeding up collision detection.
     * Return TURE when NO self collision we can guarantee, otherwise return FALSE.
     */
    inline Boolean SelfCollisionCulling() const { return FALSE; }
    inline static Boolean SelfCollisionCulling(const mine_t* node) { return FALSE; }

private:
    /* The default constructor is hide */
    mine_t() {}

    /* The bounding volume */
    BV_t        _bv;

    /* The tree which node belongs to */
    BVTree_CBT<mine_t> *_tree;

    /* Index query */
    inline Int32 getNodeIndex() const {
        Int32 res = (Int32)(this - _tree->_nodeList);
        BOOST_ASSERT(res >= 0 && res < _tree->_nodeNum);
        return res;
    }
    inline Boolean isLeaf() const {
        Int32 index = getNodeIndex() - (_tree->_nodeNum - _tree->_leafNum);
        return index >= 0 && index < _tree->_leafNum;
    }
    inline Int32 getLeafIndex() const {
        BOOST_ASSERT(isLeaf());
        return getNodeIndex() - (_tree->_nodeNum - _tree->_leafNum);
    }

    /* The friends */
    friend BVTree_CBT<mine_t>;
};

/* The bounding volume node of Complete Binary Tree BVTree.
 * WITH Normal Cone self-collision culling strategy.
 */
template <typename BV_t, typename NC_t>
class BVNode<BVTREE_TYPE_CBT, BV_t, NC_t> {
private:
    typedef BVNode<BVTREE_TYPE_CBT, BV_t, NC_t> mine_t;
public:
    /* The bounding volume type definition */
    typedef BV_t BV;

    /* The normal cone type definition */
    typedef NC_t NC;

    /* Root node check */
    inline Boolean IsRoot() const { return this == _tree->_nodeList; }

    /* Leaf node check */
    inline Boolean IsLeaf() const { return isLeaf(); }

    /* Get the corresponding mesh face of current leaf node */
    MeshFace GetLeafMeshFace() const {
        Int32 leafIndex = getLeafIndex();
        Int32 faceIndex = _tree->_leafIndexList[leafIndex];
        return _tree->_mesh->GetFace(faceIndex);
    }

    /* Get the depth of current node in tree
     * Note: the depth of root is 0
     */
    Int32 GetDepth() const {
        Int32 index = getNodeIndex() + 1;
        Int32 depth = -1;
        while(index != 0) {
            ++depth;
            index >>= 1;
        }
        return depth;
    }

    /* Parent node query
     * Note: return NULL when current node is root.
     */
    inline mine_t* GetParent() const {
        if(IsRoot()) return NULL;
        Int32 index = (getNodeIndex() - 1) / 2;
        return _tree->_nodeList + index;
    }

    /* Child node query
     * Note: return NULL when current node has no left/right child
     */
    inline mine_t* GetChildLeft() const {
        if(isLeaf()) return NULL;
        Int32 index = getNodeIndex() * 2 + 1;
        return _tree->_nodeList + index;
    }
    inline mine_t* GetChildRight() const {
        if(isLeaf()) return NULL;
        Int32 index = getNodeIndex() * 2 + 2;
        return _tree->_nodeList + index;
    }

    /* Update node state */
    void Update() {
        if(!isLeaf()) {
            // in our case (the complete binary tree), 
            // every internal node has both leaf and right child,
            // so we merge BVs (& NCs) of both childs.
            mine_t* lchild = GetChildLeft();
            mine_t* rchild = GetChildRight();
            _bv = BV_t::Merge(lchild->_bv, rchild->_bv);
            _nc = NC_t::Merge(lchild->_nc, rchild->_nc);
        } else {
            // get the bv of a leaf triangle, then update BV
            MeshFace triangle = GetLeafMeshFace();
            _bv.Update(triangle);
            _nc.Update(triangle);
        }
    }

    /* Collision culling
     * Check whether two mesh region collide, which is useful for
     * speeding up collision detection.
     * Return TURE when NO collision we can guarantee, otherwise return FALSE.
     */
    inline Boolean CollisionCulling(const mine_t* another) const { return CollisionCulling(this, another); }
    inline static Boolean CollisionCulling(const mine_t* first, const mine_t* second) { return !first->_bv.Intersect(second->_bv); }

    /* Self collision culling
     * Check whether the mesh region has a self collision, which is useful for
     * speeding up collision detection.
     * Return TURE when NO self collision we can guarantee, otherwise return FALSE.
     */
    inline Boolean SelfCollisionCulling() const { return _nc.Validate(); }
    inline static Boolean SelfCollisionCulling(const mine_t* node) { return node->_nc.Validate(); }

private:
    /* The default constructor is hide */
    mine_t() {}

    /* The bounding volume */
    BV_t        _bv;

    /* The normal cone */
    NC_t        _nc;

    /* The tree which node belongs to */
    BVTree_CBT<mine_t> *_tree;

    /* Index query */
    inline Int32 getNodeIndex() const {
        Int32 res = (Int32)(this - _tree->_nodeList);
        BOOST_ASSERT(res >= 0 && res < _tree->_nodeNum);
        return res;
    }
    inline Boolean isLeaf() const {
        Int32 index = getNodeIndex() - (_tree->_nodeNum - _tree->_leafNum);
        return index >= 0 && index < _tree->_leafNum;
    }
    inline Int32 getLeafIndex() const {
        BOOST_ASSERT(isLeaf());
        return getNodeIndex() - (_tree->_nodeNum - _tree->_leafNum);
    }

    /* The friends */
    friend BVTree_CBT<mine_t>;
};

#pragma endregion

} // end of namespace geom
LLIB_END

#endif
